package com.zlc.atonce.huarongdao.gui;

import com.zlc.atonce.Util.Point;
import com.zlc.atonce.huarongdao.algorithme.Cell;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

class MyLabel extends Label {
    public static final int MARGIN_VALUE = 3;
    public static final Background BACKGROUND_DEFAULT = new Background(new BackgroundFill(Color.GHOSTWHITE, null, null));
    public static final Background BACKGROUND_COMBINED_DEFAULT = new Background(new BackgroundFill(Color.GREEN, null, null));
    public static final Background BACKGROUND_SELECTED = new Background(new BackgroundFill(Color.GREEN, new CornerRadii(10), null));
    public static final Background BACKGROUND_COMBINED_SELECTED = new Background(new BackgroundFill(Color.GOLD, null, null));
    private final BooleanProperty selected = new SimpleBooleanProperty();
    private final BooleanProperty combined = new SimpleBooleanProperty(false);
    private final List<MyLabel> related = new ArrayList<>();
    public Point pos;

    public MyLabel(int row, int col) {
        super();
        this.pos = Point.of(row, col);
        setBackground(BACKGROUND_DEFAULT);

        selected.addListener(e -> invalidateColor());
        combined.addListener(e -> invalidateColor());

    }

    public static void combine(MyLabel... comb) {
        if (comb == null || comb.length <= 0) {
            return;
        }
        MyLabel myLabel = comb[0];
        if (comb.length > 1) {
            for (int i = 1; i < comb.length; i++) {
                comb[i].selected().bindBidirectional(myLabel.selected());
            }
        }

        Map<Point, MyLabel> map = Arrays.stream(comb).collect(Collectors.toMap(l -> l.pos, Function.identity()));
        for (MyLabel thisLabel : comb) {
            thisLabel.setCombined(true);
            thisLabel.related.clear();
            thisLabel.related.addAll(List.of(comb));
            thisLabel.related.remove(thisLabel);
            Point right = thisLabel.pos.right();
            MyLabel rightl = map.get(right);
            Insets margin = GridPane.getMargin(thisLabel);
            if (rightl != null) {
                computeMargin(thisLabel, 0, -MARGIN_VALUE, 0, 0);
                computeMargin(rightl, 0, 0, 0, -MARGIN_VALUE);
            }

            Point down = thisLabel.pos.down();
            MyLabel downl = map.get(down);
            if (downl != null) {
                computeMargin(downl, 0, 0, -MARGIN_VALUE, 0);
                computeMargin(thisLabel, -MARGIN_VALUE, 0, 0, 0);
            }


        }
    }

    private static void computeMargin(MyLabel thisLabel, int top, int right, int down, int left) {
        Insets now = GridPane.getMargin(thisLabel);
        Insets insets = new Insets(now.getTop() + top, now.getRight() + right, now.getBottom() + down, now.getLeft() + left);
        GridPane.setMargin(thisLabel, insets);

    }

    public char getCode() {
        if (!isCombined()) {
            return Cell.BLANK.charCode;
        } else {
            if (related.isEmpty()) {
                return Cell.SINGLE.charCode;

            } else if (related.size() == 3) {
                if (hasRight()) {
                    if (hasDown()) {
                        return Cell.FOUR_LU.charCode;
                    } else {
                        return Cell.FOUR_LD.charCode;
                    }
                } else {
                    if (hasDown()) {
                        return Cell.FOUR_RU.charCode;
                    } else {
                        return Cell.FOUR_RD.charCode;
                    }
                }
            } else if (related.size() == 1) {
                if (hasRight()) {
                    return Cell.TWO_LEFT.charCode;
                } else if (hasLeft()) {
                    return Cell.TWO_RIGHT.charCode;
                } else if (hasUp()) {
                    return Cell.TWO_DOWN.charCode;
                } else if (hasDown()) {
                    return Cell.TWO_UP.charCode;
                }
            }
        }
        System.out.println("未知的编码： " + this.pos);
        return Cell.BLANK.charCode;
    }

    private boolean hasRight() {
        for (MyLabel myLabel : related) {
            if (myLabel.pos.getY() > pos.getY()) {
                return true;
            }
        }
        return false;
    }

    private boolean hasLeft() {
        for (MyLabel myLabel : related) {
            if (myLabel.pos.getY() < pos.getY()) {
                return true;
            }
        }
        return false;
    }

    private boolean hasUp() {
        for (MyLabel myLabel : related) {
            if (myLabel.pos.getX() < pos.getX()) {
                return true;
            }
        }
        return false;
    }

    private boolean hasDown() {
        for (MyLabel myLabel : related) {
            if (myLabel.pos.getX() > pos.getX()) {
                return true;
            }
        }
        return false;
    }

    public boolean isSelected() {
        return selected.get();
    }

    public void setSelected(boolean selected) {
        this.selected.set(selected);
    }

    public BooleanProperty selected() {
        return selected;
    }

    public boolean isCombined() {
        return combined.get();
    }

    public void setCombined(boolean combined) {
        this.combined.set(combined);
    }

    private void invalidateColor() {
        if (!isSelected()) {
            if (isCombined()) {
                setBackground(BACKGROUND_COMBINED_DEFAULT);
            } else {
                setBackground(BACKGROUND_DEFAULT);
            }

        } else {
            if (isCombined()) {
                setBackground(BACKGROUND_COMBINED_SELECTED);
            } else {
                setBackground(BACKGROUND_SELECTED);
            }
        }
    }
}
